 
/* 
 * Copyright (C) Ignacio Lucas
 */
 
/*
 *  object_pool, hecho por Ignacio Lucas
 *
 *  object_pool implementa un vector a punteros que representan objetos en un pool.
 *  Cada pool es capaz de administrar objetos del mismo tamanio.
 *  Se pueden manejar una combinacion de las siguientes funcionalidades:
 *  - un pool de tamanio fijo prealocado.
 *  - un pool incremental, pudiendo definir el tamanio de incremento y cual es la maxima cantidad de incrementos permitida.
 *
 *  Ejemplo
 *  Tamanio de objeto: 256 bytes.
 *  Pool de tamanio fijo: 1024
 *  Pool incremental: incrementos de a 256 objetos por vez, permitiendo un total de 8 incrementos.

 * Esto significa que:
 * - se tiene un total de 1024*256 bytes=256 Kbytes de memoria fija para el pool fijo.
 * - si se necesita mas memoria, se agregan hasta 8 bloques de 256 objetos cada uno. Esto significa que se puede
 *   tener hasta 2048 objetos extra en el pool, ademas de los 1024 del pool fijo.
 * 
 * Siempre que se requiere memoria, se intenta tomar del pool fijo. Si no hay objetos libres en ese pool, se busca
 * en el pool incremental. Si en ninguno de los dos casos hay un objeto libre y es posible agregar un bloque mas
 * al pool incremental, se agrega un nuevo bloque y se toma una porcion del nuevo bloque para proveer el espacio de memoria
 * solicitado.
 *
 *  Ignacio Lucas <ignacio.lucas@gmail.com>
 *
 */
#if !defined(OBJECT_POOL_H)
#define OBJECT_POOL_H

#define OBJECT_POOL_MAX_NAME_LENGTH 64

// configuracion de un pool.
typedef struct s_object_pool_conf
{
	size_t  object_size;   // tamanio de la unidad del pool.
	int	incremental_length; // cantidad de objetos que se agregan en el mecanismo incremental.
	int	max_incremental_steps; // cuantas veces se agranda el pool incremental. Cada vez que se agranda, se agregan "incremental_length" unidades.
	int	fixed_length;  // cantidad de unidades del pool fijo.
	int   exclusive;	// 1 si precisa un acceso sincronizado a este pool.
	int id;   // identificador asignado al object_pool.
	char name[OBJECT_POOL_MAX_NAME_LENGTH]; // nombre asignado al pool. Descriptivo para loguear.

} object_pool_conf;

// estructura asociada al pool fijo.
typedef struct s_object_pool_fixed_size
{
	unsigned char *pool;  // puntero al espacio de memoria que contiene el pool de objetos.
	int position; // referencia a la posicion de este pool dentro de un vector. Aplicable para el pool incremental.
	unsigned char **indirection_pool;  // pool de indireccion para referenciar a las unidades libres y ocupadas dentro del pool.
	object_pool_conf *conf;   // configuracion del pool.
	unsigned char *first_item_address;  // puntero al primer elemento del pool.
	unsigned char *last_item_address;   // puntero al ultimo elemento del pool.
	size_t free;	

} object_pool_fixed_size;

// estructura asociada al pool incremental, construido a partir de una lista de pools fijos.
typedef struct s_object_pool_incremental
{
	object_pool_fixed_size **bufs;	// ordenados por first_item_address para buscar rapidamente un buf a partir de un puntero.
	object_pool_conf *conf;  // configuracion del pool incremental.
	size_t used; // cuantos items de bufs son validos.
	size_t free; // total de elementos libres dentro de todos los bufs "used".
	int cache_free_buf; // ultimo position de bufs donde encontre elementos libres.
	
} object_pool_incremental;

// estructura de un pool completo: parte fija y parte incremental.
typedef struct s_object_pool
{
	object_pool_conf conf;
	object_pool_fixed_size fixed_pool;
	object_pool_incremental incremental_pool;
	/* 
	flags que indican que tipos de pools estan habilitados:
	(pools_enabled & POOL_FIXED_ENABLED == 1) significa que el pool fijo es utilizable.
	(pools_enabled & POOL_INCREMENTAL_ENABLED == 1) significa que el pool incremental es utilizable.
	*/
	int pools_enabled;  
	int id;   // identificador asignado al object_pool.
	
} object_pool;

// inicializacion del object_pool.
int object_pool_init(object_pool *op, object_pool_conf *conf);

// devolucion de un objeto al pool.
int object_pool_put_or_free(object_pool *pool, void *object);

// tomar un objeto del pool.
void * object_pool_pick_or_alloc(object_pool *pool);

// destruir el object_pool.
int object_pool_destroy(object_pool *op);

// funcion a realizar sobre todos los objetos del pool (en esta version no es utilizado).
int object_pool_operate(object_pool *op, int (*fun_pool)(void*));

#endif
